package com.yuandian.business.monitor.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuandian.api.business_monitor.po.AlarmParams;
import com.yuandian.api.business_monitor.po.QueryBusinessOverviewParams;
import com.yuandian.api.business_monitor.po.SystemOverviewParams;
import com.yuandian.api.business_monitor.vo.*;
import com.yuandian.api.management.entity.ConfGraph;
import com.yuandian.api.management.entity.ConfNodeProperty;
import com.yuandian.api.management.entity.ConfStep;
import com.yuandian.api.management.entity.ConfSystem;
import com.yuandian.api.management.enums.GraphType;
import com.yuandian.api.management.feign.*;
import com.yuandian.api.management.vo.StepExportVo;
import com.yuandian.base.service.ITaskDataService;
import com.yuandian.bpm.common.core.constant.CommonConstants;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.business.monitor.mapper.BusinessOverviewMapper;
import com.yuandian.business.monitor.service.IBusinessOverviewService;
import com.yuandian.business.monitor.service.IUserOperationsService;
import com.yuandian.constant.Constants;
import com.yuandian.enums.BaseTableName;
import com.yuandian.enums.ScaleTypeEnum;
import com.yuandian.exception.SqlTemplateException;
import com.yuandian.po.BaseSearch;
import com.yuandian.po.MergeDataConfig;
import com.yuandian.po.MergeField;
import com.yuandian.utils.*;
import com.yuandian.utils.poi.ExcelTitleUtils;
import com.yuandian.utils.poi.ExcelUtil;
import com.yuandian.vo.TrendDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * 说明：业务概况service实现
 *
 * @Author yanjun
 * @Date 2020/10/26 16:14
 */
@Slf4j
@Service
public class BusinessOverviewServiceImpl implements IBusinessOverviewService {

	@Autowired
	private RemoteSystemService remoteSystemService;
	@Autowired
	private RemoteSegmentService remoteSegmentService;
	@Autowired
	private RemoteBusinessService remoteBusinessService;
	@Autowired
	private BusinessOverviewMapper businessOverviewMapper;
	@Autowired
	private IUserOperationsService userOperationsService;
	@Autowired
	private ITaskDataService taskDataService;
	@Autowired
	private RemoteItRoadMapService remoteItRoadMapService;
	@Autowired
	private RemoteStepService remoteStepService;
	@Autowired
	private RemoteResourceService remoteResourceService;
	@Autowired
	private RemoteNodePropertyService remoteNodePropertyService;


	/**
	 * 分页查询业务概况列表
	 *
	 * @param params 业务概况查询参数
	 * @return 通用返回对象
	 */
	@Override
	public PageDataInfo queryBusinessOverviewListPage(QueryBusinessOverviewParams params) {
		if (ObjectUtil.isEmpty(params.getOrderByColumn())) {
			params.setOrderByColumn("visitCount");
			params.setIsAsc("desc");
		}
		// 1、设置分页对象，如果不传pageNum或pageSize，相当于不分页
		Page<BusinessOverviewVo> page = null;
		if (params.getPageNum() > 0) {
			page = new Page<>(params.getPageNum(), params.getPageSize());
		}
		// 2、执行查询
		List<BusinessOverviewVo> list = businessOverviewMapper.queryBusinessOverviewList(page, params);
		// 3、返回分页对象
		if (page == null) {
			return new PageDataInfo(list.size(), list);
		}
		return new PageDataInfo(page, list);
	}


	/**
	 * 导出业务概况列表Excel文件
	 *
	 * @param params   业务概况查询参数
	 * @param response 响应上下文
	 * @return 文件路径
	 */
	@Override
	public void exportBusinessOverviewList(QueryBusinessOverviewParams params, HttpServletResponse response) throws IOException {
		//取消分页
		params.setPageNum(1);
		params.setPageSize(-1);
		//调用查询方法
		List<BusinessOverviewVo> boVoList = (List<BusinessOverviewVo>) queryBusinessOverviewListPage(params).getData();
		if (params.getTableNameList() != null && params.getTableNameList().size() > 0) {
			PageDataInfo pageDataInfo = queryBusinessOverviewListPage(params);
			boVoList = (List<BusinessOverviewVo>) pageDataInfo.getData();
		}
		String title = "业务概况列表";
		List<String> titleParams = new ArrayList<>();
		titleParams.add(title);
		ConfSystem system = remoteSystemService.getSystemById(params.getSystemId()).getData();
		if (ObjectUtil.isNotEmpty(system)) {
			titleParams.add(system.getName());
		}
		String formTitleName = ExcelTitleUtils.formTitleName(titleParams, params.getStartTime(), params.getEndTime());
		int index = 1;
		for (BusinessOverviewVo businessOverviewVo : boVoList) {
			businessOverviewVo.setId(index++);
			//为成功率和健康度添加%
			businessOverviewVo.setHealthRate(businessOverviewVo.getHealthRate() + "%");
			businessOverviewVo.setSuccessRate(businessOverviewVo.getSuccessRate() + "%");
			//转换平均处理时长格式
			businessOverviewVo.setAvgResponseTime(YDateUtil.getMinSecond(Double.parseDouble(businessOverviewVo.getAvgResponseTime()) / 1000));
			businessOverviewVo.setAvgClientFreeTime(YDateUtil.getMinSecond(Double.parseDouble(businessOverviewVo.getAvgClientFreeTime()) / 1000));
			businessOverviewVo.setAvgTranslateTime(YDateUtil.getMinSecond(Double.parseDouble(businessOverviewVo.getAvgTranslateTime()) / 1000));
			businessOverviewVo.setServerAvgResponseTime((YDateUtil.getMinSecond(Double.parseDouble(String.valueOf(businessOverviewVo.getServerAvgResponseTime())) / 1000)));


		}
		//列标题
		List<List<String>> headList = new ArrayList<>();
		List<String> titleList = Arrays.asList("序号", "业务名称", "访问量", "完整访问量", "平均处理时长", "告警访问量", "失败访问量", "成功访问量", "成功率", "健康度", "平均客户端耗时", "平均网络传输耗时", "平均服务端耗时", "打开页面数", "跳转页面数");
		titleList.forEach(s -> {
			List<String> childHeadList = new ArrayList<>();
			childHeadList.add(formTitleName);
			childHeadList.add(s);
			headList.add(childHeadList);
		});
		ExcelUtil.writeExcel(BusinessOverviewVo.class, formTitleName, title, boVoList, headList, response);
	}

	/**
	 * 导出业务概况列表Excel文件
	 *
	 * @param params   业务概况查询参数
	 * @param response
	 */
	@Override
	public void exportBusinessOverviewListCopy(QueryBusinessOverviewParams params, HttpServletResponse response) throws IOException {

		params.setPageNum(1);
		//由于mybatis-plus 分页查询限制 500 条,小于0 如 -1 不受限制
		params.setPageSize(-1);
		List<BusinessOverviewVo> boVoList = new ArrayList<>();
		PageDataInfo pageDataInfo = queryBusinessOverviewListPage(params);
		boVoList = (List<BusinessOverviewVo>) pageDataInfo.getData();
		String excelName = "";
		//设置标题名
		if (ObjectUtil.isNotEmpty(boVoList)) {
			excelName = "业务总览列表-" + boVoList.get(0).getSystemName() + "系统" + Constants.DOUBLE_SPACE + params.getStartTime() + "~" + params.getEndTime();
		} else {
			excelName = "业务总览列表" + Constants.DOUBLE_SPACE + params.getStartTime() + "~" + params.getEndTime();
		}
		List<BusinessOverviewCopyVo> BusinessOverviewCopyVos = BeanUtil.copyToList(boVoList, BusinessOverviewCopyVo.class);
		//设置序号和添加百分号以及修改平均响应耗时
		int index = 1;
		for (BusinessOverviewCopyVo businessOverviewVo : BusinessOverviewCopyVos) {
			businessOverviewVo.setId(index++);
			businessOverviewVo.setHealthRate(businessOverviewVo.getHealthRate() + "%");
			businessOverviewVo.setSuccessRate(businessOverviewVo.getSuccessRate() + "%");
			//转化为分秒毫秒
			double serverAvgResponseTime = 0;
			Double serverAvgResponseTime1 = Double.valueOf(businessOverviewVo.getServerAvgResponseTime());
			if (serverAvgResponseTime1 >= 60000000) {
				serverAvgResponseTime = (double) serverAvgResponseTime1 / 60000000;
				BigDecimal b = new BigDecimal(serverAvgResponseTime);
				serverAvgResponseTime = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
				businessOverviewVo.setServerAvgResponseTimeStr(serverAvgResponseTime + "分");
			} else if (serverAvgResponseTime1 >= 1000000) {
				serverAvgResponseTime = (double) serverAvgResponseTime1 / 1000000;
				BigDecimal b = new BigDecimal(serverAvgResponseTime);
				serverAvgResponseTime = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
				businessOverviewVo.setServerAvgResponseTimeStr(serverAvgResponseTime + "秒");
			} else {
				serverAvgResponseTime = (double) serverAvgResponseTime1 / 1000;
				BigDecimal b = new BigDecimal(serverAvgResponseTime);
				serverAvgResponseTime = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
				businessOverviewVo.setServerAvgResponseTimeStr(serverAvgResponseTime + "毫秒");
			}
		}
		//列标题
		List<List<String>> headList = new ArrayList<>();
		List<String> titleList = Arrays.asList("序号", "业务名称", "访问量", "交易量", "平均响应耗时", "失败数", "告警数", "成功率", "健康度");
		String finalExcelName = excelName;
		titleList.forEach(s -> {
			List<String> childHeadList = new ArrayList<>();
			childHeadList.add(finalExcelName);
			childHeadList.add(s);
			headList.add(childHeadList);
		});
		ExcelUtil.writeExcel(BusinessOverviewCopyVo.class, excelName, "业务总览列表", BusinessOverviewCopyVos, headList, response);
	}

	/**
	 * 根据系统ID、业务编码和时间范围查询业务健康度、成功率等环形图信息
	 *
	 * @param params
	 * @return 返回通用结果集
	 */
	@Override
	public BusinessOverviewVo getBuinessPercen(QueryBusinessOverviewParams params) {
		BusinessOverviewVo res = businessOverviewMapper.queryBusinessDate(params);

		//查询用户操作统计、异常用户操作统计
		if (res != null) {
			int cnt = userOperationsService.queryBusiUserCount(params.getStartTime(), params.getEndTime(), params.getSystemId(), params.getBusinessCode());
			res.setUserNum(cnt);
			cnt = userOperationsService.queryBusiUserExcepitonCount(params.getStartTime(), params.getEndTime(), params.getSystemId(), params.getBusinessCode());
			res.setExceptionUserNum(cnt);
			return res;
		}
		return new BusinessOverviewVo();
	}

	/**
	 * 根据系统编码、业务编码和时间范围查询业务健康度、访问量、平均响应时长（业务监控详情页折线数据源）
	 *
	 * @param params 查询参数
	 * @return 业务健康度、访问量、平均响应时长结果集
	 */
	@Override
	public TrendDataVo getBuinessLineChartData(QueryBusinessOverviewParams params) {
		//查询的结束时间不能大于统计时间
		params.setEndTime(taskDataService.getTrendObject(BaseTableName.BUSI_DETAIL_STAT.getName(), params.getStartTime(), params.getEndTime(), null).getTrendEndTime());
		String startTimeStr = params.getStartTime();
		String endTimeStr = params.getEndTime();

		List<BusinessLineVo> list = businessOverviewMapper.queryBuinessLineChartData(params);
		// 5、归并数据
		List<MergeField> mergeFieldList = new ArrayList<>();
		mergeFieldList.add(new MergeField("visitCount"));
		mergeFieldList.add(new MergeField("totalServerResponseTime"));
		mergeFieldList.add(new MergeField("alarmVisitCount"));
		mergeFieldList.add(new MergeField("completeVisitCount"));
		Map<String, Object> map = MergeDataUtil.mergeData(
				new MergeDataConfig.Builder(
						BusinessLineVo.class,
						list,
						params.getStartTime(),
						params.getEndTime(),
						mergeFieldList
				).cycleTimeKey("labelTime")
						.labelTimeFormatter("MM-dd'\n'HH:mm")
						.scale(params.getScale())
						.build()
		);

		Map<String, Object> resFieldMap = (Map<String, Object>) map.get("resFieldMap");
		resFieldMap.put("healthRateList", new ArrayList<>());
		resFieldMap.put("avgServerResponseTime", new ArrayList<>());
		List<Object> alarmVisitCountList = (List<Object>) resFieldMap.get("alarmVisitCountList");
		List<Object> visitCountList = (List<Object>) resFieldMap.get("visitCountList");
		List<Object> totalServerResponseTimeList = (List<Object>) resFieldMap.get("totalServerResponseTimeList");
//        List<Object> completeVisitCountList = (List<Object>) resFieldMap.get("completeVisitCountList");
		List<Object> healthRateList = (List<Object>) resFieldMap.get("healthRateList");
		List<Object> avgServerResponseTimeList = (List<Object>) resFieldMap.get("avgServerResponseTime");


		for (int i = 0; i < visitCountList.size(); i++) {
			if ((double) visitCountList.get(i) == 0D) {
				avgServerResponseTimeList.add(0D);
				healthRateList.add(0D);
			} else {
				avgServerResponseTimeList.add((double) totalServerResponseTimeList.get(i) / (double) visitCountList.get(i));
				healthRateList.add(Double.valueOf(new BigDecimal(((double) visitCountList.get(i) - (double) alarmVisitCountList.get(i)) / (double) visitCountList.get(i) * 100).setScale(2, RoundingMode.HALF_UP).toString()));
			}
		}

		// 计算周平均、月平均、历史峰值
		String endTime = YDateUtil.format(new Date(), Constants.YYYY_MM_DD_00_00_00);
		String weekStartTime = YDateUtil.getBeforeDayTime(endTime, 7);
		params.setStartTime(weekStartTime);
		params.setEndTime(endTime);
		int weekAvgValue = businessOverviewMapper.queryAvgIndicatorValue(params);	// 周平均值

		String monthStartTime = YDateUtil.getBeforeDayTime(endTime, 30);
		params.setStartTime(monthStartTime);
		int monthAvgValue = businessOverviewMapper.queryAvgIndicatorValue(params);	// 月平均值
		BusinessAvgAndPeakVo avgAndPeakVo = new BusinessAvgAndPeakVo();

		// 历史峰值
		params.setStartTime(startTimeStr);
		params.setEndTime(endTimeStr);
		queryPeakValue(avgAndPeakVo, params);

		avgAndPeakVo.setWeekAvgValue(weekAvgValue);
		avgAndPeakVo.setWeekStartTime(weekStartTime);
		avgAndPeakVo.setWeekEndTime(endTime);
		avgAndPeakVo.setMonthAvgValue(monthAvgValue);
		avgAndPeakVo.setMonthStartTime(monthStartTime);
		avgAndPeakVo.setMonthEndTime(endTime);

		resFieldMap.put("avgAndPeakVo", avgAndPeakVo);

		TrendDataVo trendDataVo = taskDataService.getTrendObject(BaseTableName.BUSI_DETAIL_STAT.getName(), params.getStartTime(), params.getEndTime(), map);
		return trendDataVo;
	}

	/**
	 * 查询历史峰值
	 * @param avgAndPeakVo 结果对象
	 * @param params	请求参数
	 */
	public void queryPeakValue(BusinessAvgAndPeakVo avgAndPeakVo, QueryBusinessOverviewParams params) {
		long startTime = System.currentTimeMillis();
		long peakValue = 0; int scale = 1;
		ExecutorService executor = null;
		String peakStartTime = "", scaleType = ScaleTypeEnum.DAY.name();

		try {
			String endTime = YDateUtil.format(new Date(), Constants.YYYY_MM_DD_00_00_00);
			List<BaseSearch> timeIntervalList = PartitionUtil.getTimeIntervalList(endTime, 5, 20);
			List<Callable<BusinessAvgAndPeakVo>> tasks = new ArrayList<>();

			// 查询数据
			for (BaseSearch timeInterval : timeIntervalList) {
				tasks.add(() -> businessOverviewMapper.queryPeakValue(params, scale, scaleType, timeInterval));
			}
			executor = Executors.newFixedThreadPool(tasks.size());
			List<Future<BusinessAvgAndPeakVo>> futures = executor.invokeAll(tasks);

			// 封装数据
			for (Future<BusinessAvgAndPeakVo> future : futures) {
				BusinessAvgAndPeakVo peakVo = future.get();
				if (peakVo != null && peakVo.getPeakValue() > peakValue) {
					peakValue = peakVo.getPeakValue();
					peakStartTime = peakVo.getPeakStartTime();
				}
			}

			avgAndPeakVo.setPeakValue(peakValue);
			avgAndPeakVo.setPeakStartTime(StringUtils.isNotEmpty(peakStartTime) ? (peakStartTime + " 00:00:00") : null);
			if (StringUtils.isNotEmpty(peakStartTime)) {
				avgAndPeakVo.setPeakEndTime(YDateUtil.getAfterDay(peakStartTime + " 00:00:00", scale));
			}

			log.info("[BPM模块]-[系统监控详情-获取 访问量 历史峰值 信息]-耗时: {} MS", System.currentTimeMillis() - startTime);

		} catch (Exception e) {
			e.printStackTrace();
			log.error("[BPM模块]-[系统监控详情-获取 访问量 历史峰值 信息]-报错: {}", e.getMessage());

		} finally {
			if (executor != null) { executor.shutdown(); }
		}


	}


	/**
	 * 根据系统ID、业务编码、时间范围查询相应的步骤分析数据
	 *
	 * @param params 查询参数
	 * @return 通用结果集
	 */
	@Override
	public R getBuinessProcessAnalysis(QueryBusinessOverviewParams params) {
		List<BusinessProcessVo> res = businessOverviewMapper.queryBuinessProcessAnalysis(params);
		if (res.isEmpty()) {
			return R.ok(res);
		}
		//查询步骤间的排序字段
		ConfStep confStep = new ConfStep();
		confStep.setSystemId(params.getSystemId());
		confStep.setBusinessCode(params.getBusinessCode());
		List<ConfStep> orderIndex = remoteStepService.list(confStep).getData();
		if (orderIndex.isEmpty()) {
			return R.ok(res);
		}
		//转化为map
		Map<String, Integer> orderIndexMap = null;
		try {
			orderIndexMap = orderIndex.stream().collect(Collectors.toMap(ConfStep::getStepCode, ConfStep::getSequence, (k1, k2) -> k2));
		} catch (Exception e) {
			String msg = String.format("业务查询->查询业务步骤排序字段异常,异常编码为:[systemId: %s] [businessCode: %s]", params.getSystemId(), params.getBusinessCode());
			log.error(msg, e);
			return R.failed("业务查询->查询业务步骤排序字段异常查询异常");
		}
		//给排序字段赋值
		for (BusinessProcessVo vo : res) {
			if (orderIndexMap.containsKey(vo.getStepCode())) {
				vo.setSequence(orderIndexMap.get(vo.getStepCode()));
			}
		}

		//根据sequence字段进行排序
		List<BusinessProcessVo> list = res.stream().sorted(Comparator.comparing(BusinessProcessVo::getSequence)).collect(Collectors.toList());
		return R.ok(list);
	}

	/**
	 * 根据系统ID、业务编码、时间范围查询步骤趋势分析数据(折线图)
	 *
	 * @param params 查询参数（系统ID、业务编码、时间范围）
	 * @return 通用结果集
	 */
	@Override
	public R getBuinessProcessTrendData(QueryBusinessOverviewParams params) {


		//查询的结束时间不能大于统计时间
		params.setEndTime(taskDataService.getTrendObject(BaseTableName.BUSI_SYS_REQ_TREND.getName(), params.getStartTime(), params.getEndTime(), null).getTrendEndTime());

		List<BusinessProcessVo> res = businessOverviewMapper.queryBuinessProcessTrendData(params);
		List<BusinessProcessVo> stepCodeList = businessOverviewMapper.queryStepCodeList(params);
		Map<String, List<BusinessProcessVo>> resMap = new HashMap<>();
		for (BusinessProcessVo processVo : stepCodeList) {
			resMap.put(processVo.getStepCode(), new ArrayList<>());
		}
		for (BusinessProcessVo businessProcessVo : res) {
			resMap.get(businessProcessVo.getStepCode()).add(businessProcessVo);
		}

		List<List<Object>> reqCounts = new ArrayList<>();
		List<List<Object>> alarmCounts = new ArrayList<>();
		List<List<Object>> totalServerResponseTimes = new ArrayList<>();
		List<List<Object>> healthRateLists = new ArrayList<>();
		List<List<Object>> avgServerResponseTimeLists = new ArrayList<>();

		Map<String, Object> map1 = null;
		List<String> stepNameList = new ArrayList<>();
		for (String stepCode : resMap.keySet()) {
			for (BusinessProcessVo processVo : stepCodeList) {
				if (processVo.getStepCode().equals(stepCode)) {
					stepNameList.add(processVo.getStepName());
				}
			}

			// 5、归并数据
			List<MergeField> mergeFieldList = new ArrayList<>();
			mergeFieldList.add(new MergeField("reqCount"));
			mergeFieldList.add(new MergeField("alarmCount"));
			mergeFieldList.add(new MergeField("totalServerResponseTime"));
			map1 = MergeDataUtil.mergeData(new MergeDataConfig.Builder(BusinessProcessVo.class, resMap.get(stepCode), params.getStartTime(), params.getEndTime(), mergeFieldList).cycleTimeKey("labelTime").labelTimeFormatter("MM-dd'\n'HH:mm").scale(params.getScale()).build());

			Map<String, Object> resFieldMap = (Map<String, Object>) map1.get("resFieldMap");
			resFieldMap.put("healthRateList", new ArrayList<>());
			resFieldMap.put("avgServerResponseTimeList", new ArrayList<>());
			List<Object> alarmCountList = (List<Object>) resFieldMap.get("alarmCountList");
			List<Object> reqCountList = (List<Object>) resFieldMap.get("reqCountList");
			List<Object> totalServerResponseTimeList = (List<Object>) resFieldMap.get("totalServerResponseTimeList");
			List<Object> healthRateList = (List<Object>) resFieldMap.get("healthRateList");
			List<Object> avgServerResponseTimeList = (List<Object>) resFieldMap.get("avgServerResponseTimeList");

			//计算健康度和平均响应时间
			for (int i = 0; i < alarmCountList.size(); i++) {
				if ((double) reqCountList.get(i) == 0D) {
					avgServerResponseTimeList.add(0D);
					healthRateList.add(0D);
				} else {
					avgServerResponseTimeList.add((double) totalServerResponseTimeList.get(i) / (double) reqCountList.get(i));
					healthRateList.add(Double.valueOf(new BigDecimal(((double) reqCountList.get(i) - (double) alarmCountList.get(i)) / (double) reqCountList.get(i) * 100).setScale(2, RoundingMode.HALF_UP).toString()));
				}
			}
			reqCounts.add(reqCountList);
			alarmCounts.add(alarmCountList);
			totalServerResponseTimes.add(totalServerResponseTimeList);
			healthRateLists.add(healthRateList);
			avgServerResponseTimeLists.add(avgServerResponseTimeList);
		}
		//当有数据时,
		if (map1 != null) {
			Map<String, Object> resFieldMap = (Map<String, Object>) map1.get("resFieldMap");
			map1.put("stepNameList", stepNameList);
			resFieldMap.put("alarmCountList", alarmCounts);
			resFieldMap.put("healthRateList", healthRateLists);
			resFieldMap.put("avgServerResponseTimeList", avgServerResponseTimeLists);
			resFieldMap.put("reqCountList", reqCounts);
			resFieldMap.put("totalServerResponseTimeList", totalServerResponseTimes);
		}

		TrendDataVo trendDataVo = taskDataService.getTrendObject(BaseTableName.BUSI_SYS_REQ_TREND.getName(), params.getStartTime(), params.getEndTime(), map1);
		return R.ok(trendDataVo);
	}


	@Override
	public List<StepExportVo> queryStepList(QueryBusinessOverviewParams params) {
		return businessOverviewMapper.queryStepList(params);

	}

	/**
	 * 获取总转换率和访问量
	 *
	 * @param params
	 * @return
	 */
	@Override
	public R getConversionRate(QueryBusinessOverviewParams params) {

		List<ConversionRateVo> res = businessOverviewMapper.getConversionRate(params);
		ConfStep confStep = new ConfStep();
		confStep.setBusinessCode(params.getBusinessCode());
		List<ConfStep> list = remoteStepService.list(confStep).getData();
		List<ConfStep> businessProcessVos = list.stream().sorted(Comparator.comparing(ConfStep::getSequence)).collect(Collectors.toList());

		List<ConversionRateVo> conversionRateVos = new ArrayList<>();
		for (int i = 0; i < businessProcessVos.size(); i++) {

			if (conversionRateVos.size() == 0) {
				for (ConversionRateVo conversionRateVo : res) {
					if (businessProcessVos.get(i).getStepCode().equals(conversionRateVo.getStepCode())) {
						conversionRateVos.add(conversionRateVo);
						break;
					}
				}
			} else {
				for (ConversionRateVo conversionRateVo : res) {
					if (businessProcessVos.get(i).getStepCode().equals(conversionRateVo.getStepCode())) {
						Double conversionRate = MathUtil.divideKeepNoFormat(Long.valueOf(conversionRateVo.getVisitCount() * 100), Long.valueOf(conversionRateVos.get(conversionRateVos.size() - 1).getVisitCount()), 2);
						conversionRateVos.get(conversionRateVos.size() - 1).setConversionRate(conversionRate > 100 ? 100 : conversionRate);
						conversionRateVos.add(conversionRateVo);
						break;
					}
				}
			}

		}
		if (conversionRateVos.size() == 1) {
			conversionRateVos.get(0).setConversionRate(100D);
		}
		conversionRateVos = conversionRateVos.stream().distinct().collect(Collectors.toList());
		Map<String, Object> hashMap = new HashMap<>();
		hashMap.put("data", conversionRateVos);
		Double totalConversionRate = 0.0D;
		if (conversionRateVos.size() > 0) {
			totalConversionRate = MathUtil.divideKeepNoFormat(Long.valueOf(conversionRateVos.get(conversionRateVos.size() - 1).getVisitCount() * 100), Long.valueOf(conversionRateVos.get(0).getVisitCount()), 2);
			totalConversionRate = totalConversionRate > 100 ? 100 : totalConversionRate;
		}

		hashMap.put("totalConversionRate", totalConversionRate);
		return R.ok(hashMap);
	}

	/**
	 * 根据系统ID、业务编码、时间范围查询网段详细信息数据
	 *
	 * @param params 查询参数（系统ID、业务编码、时间范围）
	 * @return 通用结果集
	 */
	@Override
	public R getSegmentDetailList(QueryBusinessOverviewParams params) {
		Page<SegmentDetailInfoVo> page = new Page<>(0, 10);
		if (params.getPageSize() > 0 && params.getPageNum() > 0) {
			page = new Page<>(params.getPageNum(), params.getPageSize());
		}
		List<SegmentDetailInfoVo> res = businessOverviewMapper.getSegmentDetailList(page, params);
		return R.ok(new PageDataInfo(page, res));
	}

	/**
	 * 根据系统ID、业务编码、时间范围查询it路径图
	 *
	 * @param params 查询参数（系统ID、业务编码、时间范围）
	 * @return 通用结果集
	 */
	@Override
	public R stepEndToEndRelation(QueryBusinessOverviewParams params) {

		// 1、获取网端总览每个端的位置信息映射关系
		ConfNodeProperty confNodeProperty = new ConfNodeProperty();
		confNodeProperty.setType(GraphType.BUSINESS_STEP_IT_ROAD_RELATIONSHIP.getType());
		confNodeProperty.setSystemId(params.getSystemId());
		confNodeProperty.setGraphId(String.valueOf(params.getSystemId()));
		log.info("1、开始调用远程服务获取业务监控详情-业务步骤IT路径图结构数据");
		R<List<Map<String, Object>>> listR = remoteItRoadMapService.segmentMonitorDetailItRoadGraph(confNodeProperty);
		int code = listR.getCode();
		if (code == CommonConstants.FAIL) {
			log.error("调用远程服务获取业务监控详情-业务步骤IT路径图结构数据失败，错误：{}", listR.getMsg());
		}
		List<Map<String, Object>> segmentList = listR.getData();
		log.info("调用远程服务获取业务监控详情-业务步骤IT路径图结构数据成功！");
		// 2、查询网端总览数据
		log.info("2、查询网端总览数据");
		Set<String> resourceCodes = remoteResourceService.getResourceBySystemIdAndBusinessCode(params.getSystemId(), params.getBusinessCode()).getData();
		List<SegmentIndicatorTrendVo> sitVoList = businessOverviewMapper.querySegmentOverviewRoad(params, resourceCodes);
		Map<Integer, SegmentIndicatorTrendVo> dataCollect = sitVoList.stream().collect(Collectors.toMap(SegmentIndicatorTrendVo::getSegmentId, vo -> vo, (k1, k2) -> k2));
		log.info("3、查询网端总览数据结束，开始组装数据");
		// 3、组装vo:bpm只填充数据内容，不改变数据结构
		mergeData(segmentList, dataCollect);
		log.info("组装数据结束");
		return R.ok(segmentList);
	}

	/**
	 *  合并数据
	 * @param segmentList 网端结构数据
	 * @param dataCollect 网端总览详情数据
	 */
	public void mergeData(List<Map<String, Object>> segmentList, Map<Integer, SegmentIndicatorTrendVo> dataCollect) {
		for (Map<String, Object> map : segmentList) {
			SegmentIndicatorTrendVo segmentIndicator = dataCollect.get(map.get("segmentId"));
			map.put("reqCount", 0);//请求量
			map.put("failReqCount", 0);//失败请求量
			map.put("alarmReqCount", 0);//告警请求量
			map.put("avgDealTime", 0);//平均处理时长
			map.put("health", 0.00f);//健康度
			if (ObjectUtil.isNotEmpty(segmentIndicator)) {//网端指标数据为空
				map.put("reqCount", segmentIndicator.getReqCount());//请求量
				map.put("failReqCount", segmentIndicator.getFailReqCount());//失败请求量
				map.put("alarmReqCount", segmentIndicator.getAlarmReqCount());//告警请求量
				map.put("avgDealTime", segmentIndicator.getAvgDealTime());//平均处理时长
				map.put("health", segmentIndicator.getHealth());//健康度
			}
			// 判断网端请求量是否为空,1则不为空，0则为空
			if (ObjectUtil.isNotEmpty(map.get("reqCount")) && (int) map.get("reqCount") > 0) {
				map.put("reqSumIsZero", 1);
			} else {
				map.put("reqSumIsZero", 0);
			}
			List<Map<String, Object>> childNodes = (List<Map<String, Object>>) map.get("childNodes");
			if(ObjectUtil.isNotEmpty(childNodes)){
				mergeData(childNodes, dataCollect);
			}

		}
	}

	/**
	 * 修改网端坐标
	 *
	 * @param params
	 * @return 通用结果集
	 */
	@Override
	public R updateSegmentPosition(QueryBusinessOverviewParams params) {
		ConfNodeProperty confNodeProperty = new ConfNodeProperty();
		confNodeProperty.setType(GraphType.BUSINESS_STEP_IT_ROAD_RELATIONSHIP.getType());
		confNodeProperty.setGraphId(params.getSystemId().toString());
		confNodeProperty.setNodeId(params.getSegmentId().toString());
		confNodeProperty.setLocationX(Double.valueOf(params.getLocationX()));
		confNodeProperty.setLocationY(Double.valueOf(params.getLocationY()));
		return remoteNodePropertyService.setNodePosition(confNodeProperty);

	}

	/**
	 * 新增网端坐标
	 *
	 * @param params
	 * @return
	 */
	@Override
	public R addSegmentPosition(QueryBusinessOverviewParams params) {

		return remoteSegmentService.addNode(transToGraph(params));
	}

	public ConfGraph transToGraph(QueryBusinessOverviewParams params) {
		ConfGraph graph = new ConfGraph();
		graph.setType(1);
		// 自定义数字
		graph.setGraphId("10");
		//x坐标值
		String locationX = params.getLocationX();
		if (ObjectUtil.isNotEmpty(locationX)) {
//			graph.setLocationX(Double.valueOf(locationX));
		}
		//x坐标值
		String locationY = params.getLocationY();
		if (ObjectUtil.isNotEmpty(locationY)) {
//			graph.setLocationY(Double.parseDouble(locationY));
		}
		//网端ID
		Integer segmentId = params.getSegmentId();
		if (ObjectUtil.isEmpty(segmentId)) {
			throw new SqlTemplateException("网端ID不能为空！");
		}
		graph.setNodeId(String.valueOf(segmentId));
		//上级网端
		Integer parentSegmentId = params.getParentSegmentId();
		if (ObjectUtil.isEmpty(parentSegmentId)) {
			throw new SqlTemplateException("上级网端ID不能为空！");
		}
		graph.setParentNodeId(String.valueOf(parentSegmentId));
		return graph;
	}

	/**
	 * 业务步骤统计列表
	 *
	 * @param params
	 * @return 通用结果集
	 */
	@Override
	public R getBusiStepStatList(QueryBusinessOverviewParams params) {
		Page<BusiStepStatVo> page = new Page<>(0, 10);
		if (params.getPageNum() > 0 && params.getPageSize() > 0) {
			page = new Page<>(params.getPageNum(), params.getPageSize());
		}
		List<BusiStepStatVo> list = businessOverviewMapper.getBusiStepStatList(page, params);
		return R.ok(new PageDataInfo(page, list));
	}

	@Override
	public void exportStepList(QueryBusinessOverviewParams params, HttpServletResponse response) throws IOException {
		params.setPageNum(1);
		//由于mybatis-plus 分页查询限制 500 条,小于0 如 -1 不受限制
		params.setPageSize(-1);

		// 调用服务
		List<List<String>> headList = new ArrayList<>();
		List<String> list = Arrays.asList("序号", "步骤名称", "步骤URL", "所属业务", "访问量", "平均处理时长", "处理时长峰值", "处理时长谷值", "平均网络传输耗时", "平均服务端耗时", "告警访问数", "失败数", "成功率", "健康度");
		List<StepExportVo> stepExportVos = new ArrayList<>();
		stepExportVos = businessOverviewMapper.queryStepList(params);
		//设置大标题
		String title = "业务步骤统计列表";
		List<String> titleParams = new ArrayList<>();
		titleParams.add(title);
		ConfSystem system = remoteSystemService.getSystemById(params.getSystemId()).getData();
		if (ObjectUtil.isNotEmpty(system)) {
			titleParams.add(system.getName());
		}
		String formTitleName = ExcelTitleUtils.formTitleName(titleParams, params.getStartTime(), params.getEndTime());
		list.forEach(s -> {
			List<String> lists = new ArrayList<>();
			lists.add(formTitleName);
			lists.add(s);
			headList.add(lists);
		});
		//防止查询结果出现空对象, 抛出 空指针异常
		boolean nullsOnly = stepExportVos.stream().allMatch(Objects::isNull);
		if (!nullsOnly) {
			// 给序号列赋值
			int index = 1;
			for (StepExportVo stepExportVo : stepExportVos) {
				stepExportVo.setNumber(index++);
			}

			stepExportVos.forEach(s -> {

				if (s.getHealthRate() != null) {
					s.setHealthRate(s.getHealthRate() + "%");
				}

				if (s.getAvgDealTime() != null) {
					s.setAvgDealTime(YDateUtil.getMinSecond(Double.parseDouble(s.getAvgDealTime()) / 1000));
				}

				if (s.getAvgServerResponseTime() != null) {
					s.setAvgServerResponseTime(YDateUtil.getMinSecond(Double.parseDouble(s.getAvgServerResponseTime()) / 1000));
				}

				if (s.getAvgTranslateTime() != null) {
					s.setAvgTranslateTime(YDateUtil.getMinSecond(Double.parseDouble(s.getAvgTranslateTime()) / 1000));
				}

				if (s.getMaxDealTime() != null) {
					s.setMaxDealTime(YDateUtil.getMinSecond(Double.parseDouble(s.getMaxDealTime()) / 1000));
				}

				if (s.getMinDealTime() != null) {
					s.setMinDealTime(YDateUtil.getMinSecond(Double.parseDouble(s.getMinDealTime()) / 1000));
				}

			});
		}

		ExcelUtil.writeExcel(StepExportVo.class, formTitleName, title, stepExportVos, headList, response);
	}

	@Override
	public PageDataInfo querySystemOverview(SystemOverviewParams params) {

		// 1、设置表信息集，默认排序
		if (ObjectUtil.isEmpty(params.getOrderByColumn())) {
			params.setOrderByColumn("visitCount");
			params.setIsAsc("desc");
		}
		// 2、执行查询
		Page<SystemOverviewVo> iPage = new Page<>(params.getPageNum(), params.getPageSize());
		List<SystemOverviewVo> systemReqDataOverviewPage = businessOverviewMapper.querySystemOverview(iPage, params);
		iPage.setRecords(systemReqDataOverviewPage);
		//3、获取系统Id集合
		List<Integer> systemIds = systemReqDataOverviewPage.stream().map(SystemOverviewVo::getId).collect(Collectors.toList());
		//通过系统id集合获取每个系统对应的业务数
		log.info("开始调用远程服务获取每个系统对应的业务数！");
		if (ObjectUtil.isNotEmpty(systemIds)) {
			R<List<Map<String, Integer>>> businessCountBySystemIdsR = remoteBusinessService.getBusinessCountBySystemIds(systemIds);
			if (businessCountBySystemIdsR.getCode() == CommonConstants.FAIL) {
				log.error("调用远程服务获取每个系统对应的业务数失败，错误信息：" + businessCountBySystemIdsR.getMsg());
				throw new SqlTemplateException(businessCountBySystemIdsR.getMsg());
			}
			log.info("调用远程服务获取每个系统对应的业务数结束！");
			List<Map<String, Integer>> data = businessCountBySystemIdsR.getData();
			Map<String, Integer> businessCountMap = new HashMap<>();
			data.forEach(e -> businessCountMap.putAll(e));
			// 5、转换业务数据
			DecimalFormat df = new DecimalFormat("0.00");
			for (SystemOverviewVo record : systemReqDataOverviewPage) {
				//转换健康度和成功率的格式,保留小数点后两位
				record.setHealthRateStr(df.format((double) record.getHealthRate()));
				record.setSuccessRateStr(df.format((double) record.getSuccessRate()));
				//回填业务个数
				record.setBusinessCount(businessCountMap.get(String.valueOf(record.getId())));
				//访问量为空时,告警访问量和失败访问量都设为0
				if (record.getVisitCount() == null) {
					record.setVisitCount(0);
					record.setAlarmVisitCount(0);
					record.setFailVisitCount(0);
				}
			}
		}
		// 6、返回结果
		return new PageDataInfo(iPage);

	}

	/**
	 * 按照系统ID、业务编码及时间范围分类统计各类型告警（告警类型环形图---业务监控详情页面）
	 *
	 * @param params 查询参数
	 * @return 返回通用结果集
	 */
	@Override
	public List<AlarmProportionVo> getBusinessMonitorAlarmPercent(AlarmParams params) {


		return businessOverviewMapper.queryBusinessMonitorAlarmTypePercent(params);
	}

}
